package arrays;

/**
 * @author pengfei.hpf
 * @date 2020/3/5
 * @verdion 1.0.0
 *
 * 实现获取下一个排列的函数，算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
 *
 * 如果不存在下一个更大的排列，则将数字重新排列成最小的排列（即升序排列）。
 *
 * 必须原地修改，只允许使用额外常数空间。
 *
 * 以下是一些例子，输入位于左侧列，其相应输出位于右侧列。
 * 1,2,3 → 1,3,2
 * 3,2,1 → 1,2,3
 * 1,1,5 → 1,5,1
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/next-permutation
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class NextPermutation {
    //TODO: 数组折叠 翻转, 找到谷底, 谷底与后续数中所有大于他的数的最小一个交换, 再将后面的数组从小到大排列
    public void nextPermutation(int[] nums){
        if(nums == null || nums.length == 0){
            return;
        }
        int lowest = nums.length - 1;
        for(int i = nums.length - 2; i >= 0; i --){
            if(nums[i + 1] > nums[i]){
                lowest = i;
                break;
            }
        }
        if(lowest == nums.length - 1){
            reverse(nums, 0, nums.length - 1);
            return;
        }
        int higher = lowest + 1;
        for(int i = higher; i <= nums.length - 1; i ++){
            if(nums[i] <= nums[lowest]){
                higher = i - 1;
                break;
            }
            higher = i;
        }

        swap(nums, lowest, higher);
        reverse(nums, lowest +1, nums.length - 1);
    }

    private void reverse(int[] nums, int start, int end){
        while(start < end){
            int t = nums[start];
            nums[start] = nums[end];
            nums[end] = t;
            start ++;
            end --;
        }
    }


    private void swap(int[] nums, int i, int j){
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}
